package com.easyoffer.sentinel;

import cn.hutool.Hutool;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.net.http.WebSocket;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Component
@Slf4j
@Data
public class SentinelConfig{
    private static final String NACOS_SERVER_ADDR = "127.0.0.1:8848";
    private static final String GROUP_ID = "DEFAULT_GROUP";

    public void init() {
//        loadFlowRules();
//        loadParamFlowRules();
//        loadDegradeRules();
//        initFlowRules();
//        initParamFlowRules();
//        initDegradeRule();
        // 获取所有流量控制规则
        List<FlowRule> flowRules = FlowRuleManager.getRules();
        log.error("flowRules:"+flowRules);
        // 获取所有降级规则
        List<DegradeRule> degradeRules = DegradeRuleManager.getRules();
        log.error("degradeRules:"+degradeRules);
        // 获取所有热点规则
        List<ParamFlowRule> paramRules = ParamFlowRuleManager.getRules();
        log.error("paramRules:"+paramRules);
    }


    /**
     * 初始化流量控制规则
     * resource：资源名，即限流规则的作用对象
     * count: 限流阈值
     * grade: 限流阈值类型，QPS 或线程数
     * strategy: 根据调用关系选择策略
     */
    private static void initFlowRules(){
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("HelloWorld");
        //限流级别
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // Set limit QPS to 20.
        rule.setCount(20);
        rules.add(rule);

        FlowRule rule1 = new FlowRule();
        rule.setResource("listQuestionBankPageVO");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS)
            .setCount(20);
        rules.add(rule1);
        FlowRuleManager.loadRules(rules);
    }

    /**
     * 热点参数限流
     * resource	资源名，必填
     * count	限流阈值，必填
     * grade	限流模式	QPS 模式
     * durationInSec	统计窗口时间长度（单位为秒），1.6.0 版本开始支持	默认1s
     * controlBehavior	流控效果（支持快速失败和匀速排队模式），1.6.0 版本开始支持	默认快速失败
     * maxQueueingTimeMs	最大排队等待时长（仅在匀速排队模式生效），1.6.0 版本开始支持	默认0ms
     * paramIdx	热点参数的索引，必填，对应 SphU.entry(xxx, args) 中的参数索引位置
     * paramFlowItemList	参数例外项，可以针对指定的参数值单独设置限流阈值，不受前面 count 阈值的限制。仅支持基本类型和字符串类型
     * clusterMode	是否是集群参数流控规则	默认false
     * clusterConfig	集群流控相关配置
     */
    private void initParamFlowRules(){
        List<ParamFlowRule> rules = new ArrayList<>();
        //根据ip限流
        ParamFlowRule rule = new ParamFlowRule("listQuestionBankPageVO")
                .setParamIdx(0) //热点参数的索引
                .setCount(3) //限流阈值
                .setGrade(RuleConstant.FLOW_GRADE_QPS) //默认QPS模式
                .setDurationInSec(5); //统计时间窗口 测试窗口5秒内3次请求则限流 生产环境下每秒50次进行封禁处理
        rules.add(rule);
        ParamFlowRuleManager.loadRules(rules);
    }

    /**
     * resource	资源名，即规则的作用对象
     * grade	熔断策略，支持慢调用比例/异常比例/异常数策略
     * count	慢调用比例模式下为慢调用临界 RT（超出该值计为慢调用）；异常比例/异常数模式下为对应的阈值
     * timeWindow	熔断时长，单位为 s
     * minRequestAmount	熔断触发的最小请求数，请求数小于该值时即使异常比率超出阈值也不会熔断（1.7.0 引入）
     * statIntervalMs	统计时长（单位为 ms），如 60*1000 代表分钟级（1.8.0 引入）
     */
    private static void initDegradeRule(){
        List<DegradeRule> rules = new ArrayList<>();
        //慢调用规则
        DegradeRule rule = new DegradeRule();
        rule.setResource("listQuestionBankPageVO");
        rule.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())
                .setCount(0.1)  // 慢调用比例
                .setSlowRatioThreshold(3000) //慢调用阈值
                .setMinRequestAmount(10) //最小请求数满足条件
                .setStatIntervalMs(60 * 1000) // 统计多长时间内的异常比例 这里设置为 60s
                .setTimeWindow(10); //熔断时间

        DegradeRule rule1 = new DegradeRule();
        rule1.setResource("listQuestionBankPageVO");
        rule1.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType())
            .setCount(0.1)
            .setMinRequestAmount(10)
            .setStatIntervalMs(10 * 1000) // 统计多长时间内的异常比例 这里设置为 10s
            .setTimeWindow(10);
        rules.add(rule);
        rules.add(rule1);
        DegradeRuleManager.loadRules(rules);
    }
}
